/**
 * 
 */
package autoUpdater.helper;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;

import autoUpdater.AutoUpdaterMain;
import autoUpdater.gui.UpdaterFrame;

/**
 * @author Christian
 * 
 */
public class Downloader implements Runnable {
	
	/**
	 * 
	 */
	private URL dlUrl = null;
	
	/**
	 * 
	 */
	private File file = null;
	
	/**
	 * 
	 */
	private int fileSize = 0;
	
	/**
	 * 
	 */
	private BufferedOutputStream bout;
	
	/**
	 * 
	 */
	private BufferedInputStream in;
	
	/**
	 * 
	 */
	private FileOutputStream fos;
	
	/**
	 * 
	 */
	private File newFile;
	
	/**
	 * 
	 */
	private UpdaterFrame frame = null;
	
	/**
	 * 
	 */
	private OnlineStatus oStatus = null;
	
	/**
	 * @author Christian
	 * @param oStatus
	 * @param frame
	 */
	public Downloader(OnlineStatus oStatus, File heldenJar, UpdaterFrame frame) {

		this.file = heldenJar;
		this.dlUrl = oStatus.getAktuelleUpdateUrl();
		this.fileSize = oStatus.getFileSize();
		this.frame = frame;
		this.oStatus = oStatus;
	}
	
	/**
	 * Diese Methode aktualisiert den Fortschrittsbalken
	 * 
	 * @param wert
	 *            neuer Fortschritt
	 */
	private void setProgress(final int wert) {

		SwingUtilities.invokeLater(new Runnable() {
			
			public void run() {

				frame.updateJProgressBar(wert);
			}
		});
	}
	
	/**
	 * 
	 * @param bool
	 *            Boolean
	 */
	private void setIndeterminate(final boolean bool) {

		SwingUtilities.invokeLater(new Runnable() {
			
			public void run() {

				frame.setIndeterminate(bool);
			}
		});
	}
	
	private void setStatusText(final String s) {

		SwingUtilities.invokeLater(new Runnable() {
			
			public void run() {

				frame.setStatusText(s);
			}
		});
	}
	
	/**
	 * @see java.lang.Runnable#run()
	 */
	public void run() {

		try {
			setIndeterminate(true);
			setStatusText("Verbinde zum Downloadserver!");
			setProgress(0);
			newFile = new File(file.getAbsolutePath() + ".temp");
			newFile.createNewFile();
			byte[] buffer = new byte[4096];
			int len = -1;
			long geladeneBytes = 0;
			long alteGeladeneBytes = 0;
			int oldprogress = 0;
			setIndeterminate(true);
			long time1 = System.currentTimeMillis() + 100;
			long time2 = 0;
			InputStream inStream = dlUrl.openStream();
			in = new BufferedInputStream(inStream);
			fos = new FileOutputStream(newFile);
			bout = new BufferedOutputStream(fos, buffer.length);
			setIndeterminate(false);
			setStatusText("Download gestartet!");
			while ((len = in.read(buffer)) != -1) {
				bout.write(buffer, 0, len);
				geladeneBytes += len;
				time2 = System.currentTimeMillis();
				if (time1 < time2) {
					StringBuilder builder = new StringBuilder();
					builder.append((geladeneBytes - alteGeladeneBytes) / 1024);
					builder.append("  KB/s");
					frame.setDownloadSpeedText(builder.toString());
					time1 = System.currentTimeMillis() + 500;
					alteGeladeneBytes = geladeneBytes;
				}
				double newProgress = ((double) geladeneBytes / (fileSize * 1024)) * 100;
				if (newProgress >= 100) {
					setProgress(99);
				} else {
					if (newProgress > oldprogress) {
						setProgress((int) newProgress);
						oldprogress = (int) newProgress;
					}
				}
				if (frame.isClosed()) {
					throw new Exception("Geschlossen Exception");
				}
			}
			setStatusText("Download fertig!");
			setProgress(100);
			bout.flush();
			bout.close();
			in.close();
			fos.close();
			// Fertig
			if (!Util.getMd5(newFile).equals(oStatus.getMd5Hash())) {
				throw new ServerNotAvailableException("Md5-Fehler");
			} else {
				if (newFile.exists()) {
					file.delete();
					if (!newFile.renameTo(file)) {
						throw new ServerNotAvailableException("Copy-Fehler");
					} else {
						JOptionPane.showMessageDialog(frame, "Update erfogreich!");
						macheAusfuehrbar(file);
					}
				}
			}
		} catch (Exception e) {
			try {
				bout.flush();
				bout.close();
				in.close();
				fos.close();
			} catch (IOException e1) {
			}
			if (newFile.exists()) {
				newFile.delete();
			}
			e.printStackTrace();
		}
	}
	
	private void macheAusfuehrbar(File heldenJar) {
		
		StringBuilder exceBuilder = new StringBuilder();
		if (AutoUpdaterMain.isDebugMode()) {
			System.out.println("change chmod");
		}
		exceBuilder.append("chmod a+x ");
		exceBuilder.append(heldenJar.getAbsolutePath());
		
		
		System.out.println(exceBuilder.toString());
		
	
		// Helden starten
		Runtime runtime = Runtime.getRuntime();
		try {
			@SuppressWarnings("unused")
			Process proc = runtime.exec(exceBuilder.toString());
			// if (UpdaterConfig.isDebugMode()) {
			// Scanner scanner = new Scanner(proc.getErrorStream());
			// while (scanner.hasNext()) {
			// System.out.println(scanner.next());
			// }
			// scanner.close();
			// }
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
